package com.benmei.ntlive.server.netty.websocket;

import com.benmei.ntlive.constant.ConnectType;
import com.benmei.ntlive.server.netty.NetLiveHandler;
import com.benmei.ntlive.server.netty.SessionRepository;
import com.benmei.ntlive.utils.ChannelUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.concurrent.ScheduledFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Create by chenhong on 2018/10/26 14:51
 * Description :
 */
@ChannelHandler.Sharable //表示此类可以分享，功能类似非单例
@Component("webSocketServerHandler")
public class WebSocketServerHandler extends ChannelHandlerAdapter {
    private static Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class);
    private WebSocketServerHandshaker handshaker;
    @Autowired
    private NetLiveHandler netLiveHandler;
    @Autowired
    private SessionRepository sessionRepository;

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error(cause.getMessage(), cause);
        ChannelUtil.exitChannelByException(ctx, cause, sessionRepository);
        ctx.close();
        ctx.fireExceptionCaught(cause);
    }

    @Override
    public void channelActive(final ChannelHandlerContext ctx) throws Exception {
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("连接断开：" + ctx.channel().remoteAddress().toString());
        String channelKey = ctx.channel().remoteAddress().toString();
        // 关闭心跳
        ScheduledFuture<?> heartBeat = sessionRepository.getTaskMap().get(channelKey);
        if (heartBeat != null) {
            logger.info(" \n       / cancel schedule task ------》》》》》》》》" + heartBeat.toString());
            boolean cancelSuccess = heartBeat.cancel(true);
            logger.info("channelInactive: 关闭心跳 for client:" + channelKey + " cancelHeartBeatSuccess:" + cancelSuccess + ", heartBeatInstance" + heartBeat.toString());
            heartBeat = null;
        }
        this.sessionRepository.remove(channelKey);
        /**
         * resive by C.H on 2018/10/29 19:37
         * 修改：移除心跳任务
         */
        sessionRepository.getTaskMap().remove(channelKey);

        logger.info("channelInactive: 移除客户端[{}]后Current room size is {}", channelKey, this.sessionRepository.size());
        // 释放资源
        ctx.close();
        logger.info("channelInactive：释放资源 for client:{}", channelKey);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {//建立连接的请求
            handleHttpRequest(ctx, (FullHttpRequest) msg);
        } else if (msg instanceof WebSocketFrame) {//WebSocket
            handleWebsocketFrame(ctx, (WebSocketFrame) msg);
        }
    }

    /**
     * websocket消息处理方法
     *
     * @param ctx
     * @param frame
     * @return: void
     * @author: C.H
     * @date: 2018/11/8 16:36
     */
    private void handleWebsocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        if (frame instanceof CloseWebSocketFrame) {//关闭
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
        } else if (frame instanceof PingWebSocketFrame) {//ping消息
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
        } else if (frame instanceof TextWebSocketFrame) {//文本消息
            String request = ((TextWebSocketFrame) frame).text();
            try {
                netLiveHandler.handler(ctx, request, ConnectType.WEBSOCKET);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 第一次连接，建立握手
     *
     * @param ctx
     * @param request
     * @return: void
     * @author: C.H
     * @date: 2018/11/8 16:34
     */
    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) {
        if (request.decoderResult().isSuccess() && "websocket".equals(request.headers().get("Upgrade"))) {
            System.out.println("websocket连接成功:" + ctx.channel().remoteAddress().toString() + " " + new Date().toString());
            WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory("ws://localhost:8080/websocket", null, false);
            handshaker = factory.newHandshaker(request);//通过创建请求生成一个握手对象
            if (handshaker != null) {
                handshaker.handshake(ctx.channel(), request);
            }
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
}
